package com.qd.admin.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.page.PageUtil;
import com.qd.common.sys.annotation.DataScope;
import com.qd.common.sys.annotation.OperatorInfo;
import com.qd.common.sys.domain.entity.login.LoginUserDTO;
import com.qd.common.sys.domain.entity.login.LoginUserDisplay;
import com.qd.common.sys.domain.entity.login.LoginUserOrgDTO;
import com.qd.common.sys.domain.entity.meun.MenuDTO;
import com.qd.common.sys.domain.login.LoginBody;
import com.qd.common.sys.domain.login.LoginStatusDTO;
import com.qd.common.sys.domain.login.LoginUser;
import com.qd.common.sys.enums.OperatorType;
import com.qd.common.sys.util.SecurityUtils;
import com.qd.system.service.person.AuthTokenService;
import com.qd.core.service.SysLoginService;
import com.qd.system.dto.PasswordDto;
import com.qd.system.service.menu.MenuHoldService;
import com.qd.system.service.menu.MenuService;
import com.qd.system.service.person.PersonHoldService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import java.util.List;
import java.util.Map;

/**
 * 登录信息
 *
 * @author sjk
 */
@RestController
@Validated
@RequiredArgsConstructor
public class LoginController {

    private final SysLoginService sysLoginService;
    private final PersonHoldService personHoldService;
    private final MenuService menuService;
    private final MenuHoldService menuHoldService;
    private final AuthTokenService authTokenService;

    private static final String PERSON_ID_NULL_MSG = "用户ID不能为空";

    /**
     * 登录
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping(value = "/sys/userLogin/login")
    public ApiResultWrapper<Object> login(@RequestBody @Validated LoginBody loginBody) {
        return ApiResult.success(sysLoginService.login(loginBody));
    }

    /**
     * 获取用户信息
     *
     * @return 登录用户信息
     */
    @GetMapping(value = "/sys/userLogin/getById")
    public LoginUserDTO getById(String personId) {
        if (!StringUtils.hasLength(personId)) {
            final LoginUser loginUser = SecurityUtils.getLoginUser();
            if (null == loginUser) {
                throw new ApiException(401, "用户不存在存在");
            }
            personId = loginUser.getUserId();
        }
        return personHoldService.getLoginUserService().getByIdDto(personId);
    }

    /**
     * 更新用户信息
     */
    @PutMapping(value = "/sys/userLogin/update")
    @OperatorInfo(title = "更新用户登录信息", operator = OperatorType.UPDATE)
    public ApiResultWrapper<Object> update(@Validated @RequestBody LoginUserDTO loginUserDTO) {
        loginUserDTO.setPersonId(SecurityUtils.getLoginUser().getUserId());
        return personHoldService.updateLoginPerson(loginUserDTO);
    }

    /**
     * 获取用户菜单信息
     *
     * @return 路由信息
     */
    @GetMapping(value = "/sys/userLogin/getMenu")
    public List<MenuDTO> getMenu() {
        final LoginUser loginUser = SecurityUtils.getLoginUser();
        final List<MenuDTO> menus = menuHoldService.getMenuList(loginUser.getUserId());
        return menuService.buildMenu(menus);
    }

    /**
     * 重置密码
     */
    @PutMapping(value = "/sys/userLogin/resetPassword")
    @OperatorInfo(title = "用户重置密码", operator = OperatorType.UPDATE)
    public ApiResultWrapper<Object> resetPassword(@Validated @RequestBody Map<String, String> map) {
        final String personId = SecurityUtils.getLoginUser().getUserId();
        final String oldPassword = map.get("oldPassword");
        final String password = map.get("password");
        final String confirmPassword = map.get("confirmPassword");
        if (!StringUtils.hasLength(personId)) {
            return ApiResult.error(PERSON_ID_NULL_MSG);
        }
        if (!StringUtils.hasLength(password)) {
            return ApiResult.error("密码不能为空");
        }
        if (!StringUtils.hasLength(confirmPassword)) {
            return ApiResult.error("确认密码不能为空");
        }
        if (!password.equals(confirmPassword)) {
            return ApiResult.error("两次输入的密码不一致");
        }
        if (password.equals(oldPassword)) {
            return ApiResult.error("请输入和旧密码不同的新密码");
        }
        final PasswordDto passwordDto = new PasswordDto();
        passwordDto.setPersonId(personId);
        passwordDto.setPassword(password);
        passwordDto.setOldPassword(oldPassword);
        passwordDto.setIsCheckOldPassword(true);
        passwordDto.setIsLoginUser(true);
        final ApiResultWrapper<Object> wrapper = personHoldService.resetPassword(passwordDto, false);
        if (wrapper.isSuccess()) {
            authTokenService.loginOut();
        }
        return wrapper;
    }

    /**
     * 修改头像
     */
    @PutMapping(value = "/sys/userLogin/updateAvatar")
    @OperatorInfo(title = "用户修改头像", operator = OperatorType.UPDATE)
    public ApiResultWrapper<Object> updateAvatar(@Validated @RequestBody Map<String, String> map) {
        final String personId = SecurityUtils.getLoginUser().getUserId();
        final String avatar = map.get("avatar");
        if (!StringUtils.hasLength(personId)) {
            return ApiResult.error(PERSON_ID_NULL_MSG);
        }
        if (!StringUtils.hasLength(avatar)) {
            return ApiResult.error("用户头像不能为空");
        }
        return personHoldService.updateAvatar(personId, avatar);
    }


    /**
     * 获得个人登录信息
     * 包含了权限、角色、部门
     */
    @GetMapping(value = "/sys/userLogin/getInfo")
    public ApiResultWrapper<Object> getInfo() {
        return personHoldService.getInfo();
    }

    /**
     * 设置登录组织
     *
     * @param LoginUserOrgDTO 登录人和机构的关系
     */
    @PutMapping(value = "/sys/userLogin/setLoginUserOrg")
    @OperatorInfo(title = "设置登录组织", operator = OperatorType.UPDATE)
    public ApiResultWrapper<Object> setLoginUserOrg(@Validated @RequestBody LoginUserOrgDTO LoginUserOrgDTO) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        final String remote = LoginUserOrgDTO.getRemote();
        final String personId = LoginUserOrgDTO.getPersonId();
        if (!StringUtils.hasLength(remote)) {
            LoginUserOrgDTO.setRemote(loginUser.getRemote());
        }
        if (!StringUtils.hasLength(personId)) {
            LoginUserOrgDTO.setPersonId(loginUser.getUserId());
        }
        return personHoldService.saveLoginUserOrg(LoginUserOrgDTO);
    }

    /**
     * 登录人列表
     *
     * @return 列表
     */
    @GetMapping(value = "/sys/userLogin/page")
    @DataScope
    public IPage<LoginUserDTO> operatorLogPage(LoginUserDTO dto) {
        return personHoldService.getLoginUserService().page(PageUtil.buildPage(dto), dto);
    }

    /**
     * 更新登录用户状态
     *
     * @return 列表
     */
    @PreAuthorize("@ps.hasAnyPermissions('system:userLogin:enable,system:userLogin:disable')")
    @PutMapping(value = "/sys/userLogin/updateLoginUserState")
    @OperatorInfo(title = "更新登录用户状态", operator = OperatorType.UPDATE)
    public ApiResultWrapper<Object> updateLoginUserState(@RequestBody LoginStatusDTO dto) {
        final Integer loginStatus = dto.getLoginStatus();
        final String personId = dto.getPersonId();
        if (null == loginStatus) {
            return ApiResult.error("登录状态不能为空");
        }
        if (!StringUtils.hasLength(personId)) {
            return ApiResult.error(PERSON_ID_NULL_MSG);
        }
        final String userId = SecurityUtils.getLoginUser().getUserId();
        if (userId.equals(dto.getPersonId())) {
            return ApiResult.error("请勿操作自己");
        }
        if (SecurityUtils.isAdmin(dto.getPersonId())) {
            return ApiResult.error("admin账号不能停用");
        }
        return authTokenService.updateLoginUserState(dto);
    }

    /**
     * 重置登录人员密码
     * 管理员重置登录人员密码
     */
    @PreAuthorize("@ps.hasPermission('system:userLogin:resetUserLoginPassword')")
    @PutMapping(value = "/sys/userLogin/resetUserLoginPassword")
    @OperatorInfo(title = "重置登录人员密码", operator = OperatorType.UPDATE)
    public ApiResultWrapper<Object> resetUserLoginPassword(@Validated @RequestBody Map<String, String> map) {
        final String personId = map.get("personId");
        final String password = map.get("password");
        final String confirmPassword = map.get("confirmPassword");
        if (!StringUtils.hasLength(personId)) {
            return ApiResult.error(PERSON_ID_NULL_MSG);
        }
        if (!StringUtils.hasLength(password)) {
            return ApiResult.error("密码不能为空");
        }
        if (!StringUtils.hasLength(confirmPassword)) {
            return ApiResult.error("确认密码不能为空");
        }
        if (!password.equals(confirmPassword)) {
            return ApiResult.error("两次输入的密码不一致");
        }
        final PasswordDto passwordDto = new PasswordDto();
        passwordDto.setPersonId(personId);
        passwordDto.setPassword(password);
        passwordDto.setIsLoginUser(false);
        passwordDto.setIsCheckOldPassword(false);
        final ApiResultWrapper<Object> wrapper = personHoldService.resetPassword(passwordDto, false);
        if (wrapper.isSuccess()) {
            authTokenService.clearLoginCache(personId);
        }
        return wrapper;
    }

    /**
     * 缓存登录用户列表
     *
     * @param loginUserDisplay 查询条件
     */
    @GetMapping(value = "/sys/userLogin/userTokenPage")
    public Page<LoginUserDisplay> userTokenPage(LoginUserDisplay loginUserDisplay) {
        return authTokenService.userTokenPage(PageUtil.buildPage(loginUserDisplay), loginUserDisplay);
    }

    /**
     * 缓存登录用户详情
     *
     * @param tokenId token
     */
    @GetMapping(value = "/sys/userLogin/userTokenDetail")
    public LoginUserDisplay userTokenDetail(@Validated @NotBlank(message = "tokenId不能为空") String tokenId) {
        return authTokenService.userTokenDetail(tokenId);
    }

    /**
     * 登录用户下线
     */
    @DeleteMapping(value = "/sys/userLogin/offlineLoginUser")
    @OperatorInfo(title = "登录用户下线", operator = OperatorType.DELETE)
    public ApiResultWrapper<Object> offlineLoginUser(@RequestBody Map<String, List<String>> map) {
        if (null == map || map.isEmpty()) {
            throw new ApiException("tokenId不能为空");
        }
        final List<String> ids = map.get("ids");
        if (null == ids || ids.isEmpty()) {
            throw new ApiException("tokenId不能为空");
        }
        authTokenService.offlineLoginUser(ids);
        return ApiResult.success("删除成功");
    }

}
